#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sikle.h"

GramelPool* GramelPool_new(unsigned int size)
{
  GramelPool* gp = (GramelPool*)malloc(sizeof(GramelPool));

  gp->size = size;
  gp->base = malloc(size);
  gp->pc = 0;

  //  printf("gpbase: %p\n", gp->base);
  return gp;
}

void GramelPool_delete(GramelPool* gp)
{
  if(gp) {
    if(gp->base)
      free(gp->base);
    free(gp);
  }
}

void GramelPool_dump(GramelPool* gp, StringPool* sp)
{
  int pc = 0;
  int count = 0;

  printf("GramelPoolBase: %p\n", gp->base);
  while(pc < gp->pc) {
    switch(GRAMEL(gp->base+pc)->type) {
    case GT_INTEGER: {
      GInteger* integer = GINTEGER(gp->base+pc);

      printf("%d:%d: INTEGER\t%d\n", count++, pc, integer->value);
      pc += sizeof(GInteger);
      break;
    }
    case GT_STRING: {
      char buff[100];
      GString* string = GSTRING(gp->base+pc);
      SPString sps = string->sps;

      strncpy(buff, sp->base + sps.offset, sps.size);
      buff[sps.size] = 0;
      printf("%d:%d: STRING\t%s\n", count++, pc, buff);
      pc += sizeof(GString);
      break;
    }
    case GT_BUILTIN_WORD: {
      GBuiltinWord* word = GBUILTINWORD(gp->base+pc);
      SPString name = word->name;
      char buff[100];

      strncpy(buff, sp->base + name.offset, name.size);
      buff[name.size] = 0;
      printf("%d:%d: BUILTIN WORD\t%s\n", count++, pc, buff);
      pc += sizeof(GBuiltinWord);
      break;
    }
    case GT_WORD: {
      GWord* word = GWORD(gp->base+pc);
      unsigned int entry = word->entry;

      printf("%d:%d: WORD\t%d\n", count++, pc, entry);
      pc += sizeof(GWord);
      break;
    }
    case GT_ANONYMOUS_WORD: {
      GAnonymousWord* word = GANONYMOUSWORD(gp->base+pc);
      unsigned int entry = word->entry;

      printf("%d:%d: ANONYMOUSWORD\t%d\n", count++, pc, entry);
      pc += sizeof(GAnonymousWord);
      break;
    }
    case GT_END: {
      printf("%d:%d: END\n", count++, pc);
      pc += sizeof(GEnd);
      break;
    }
    }
  }
}

void GramelPool_put(GramelPool* gp, Gramel* gramel)
{
  // printf("GramePool_put:gpbase: %p %d\n", gp->base, gramel->type);
  switch(gramel->type) {
  case GT_INTEGER: {
    GInteger* integer = GINTEGER(gramel);
    *GINTEGER(gp->base+gp->pc) = *integer;
    gp->pc += sizeof(GInteger);
    break;
  }
  case GT_STRING: {
    GString* string = GSTRING(gramel);
    *GSTRING(gp->base+gp->pc) = *string;
    gp->pc += sizeof(GString);
    break;
  }
  case GT_BUILTIN_WORD: {
    GBuiltinWord* word = GBUILTINWORD(gramel);
    *GBUILTINWORD(gp->base+gp->pc) = *word;
    gp->pc += sizeof(GBuiltinWord);
    break;
  }
  case GT_WORD: {
    GWord* word = GWORD(gramel);
    *GWORD(gp->base+gp->pc) = *word;
    gp->pc += sizeof(GWord);
    break;
  }
  case GT_ANONYMOUS_WORD: {
    GAnonymousWord* word = GANONYMOUSWORD(gramel);
    *GANONYMOUSWORD(gp->base+gp->pc) = *word;
    gp->pc += sizeof(GAnonymousWord);
    break;
  }
  case GT_END: {
    GEnd* end = GEND(gramel);
    *GEND(gp->base+gp->pc) = *end;
    gp->pc += sizeof(GEnd);
    break;
  }
  default:
    printf("Unkown Gramel Type\n");
    exit(0);
  }
}
